package com.green_reading.mandolin;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_17;
import org.java_websocket.handshake.ServerHandshake;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import butterknife.BindView;
import butterknife.ButterKnife;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;

public class MainActivity extends Activity implements AdapterView.OnItemClickListener {
    private final static String TAG = MainActivity.class.getCanonicalName();
    private static final int REQUEST_LOGIN = 0;
    private static final int REQUEST_CHAT = 1;

    private WebSocketClient websocketClient;
    private String userName;
    private Integer userId = -1;
    private boolean loginInSuccess = false;
    private Map<Integer, Map<String, String>> contacts_infos = null;
    private Map<String, Map<String, String>> contacts_map = null;
    private DBManager dbManager;
    private ScheduledExecutorService executorSendMessage;
    private ScheduledExecutorService executor;

    @BindView(R.id.contacts_view) ListView contacts_view;

    protected void toast(final String msg) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.main);
        ButterKnife.bind(this);
        dbManager = new DBManager(this);
        executorSendMessage = Executors.newSingleThreadScheduledExecutor();
        executor = Executors.newSingleThreadScheduledExecutor();

        Intent intent = new Intent(this, LoginActivity.class);
        startActivityForResult(intent, REQUEST_LOGIN);
        //recoLiveInit("p2p0.reconova.com:3000", "");
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_LOGIN) {
            if (resultCode == RESULT_OK) {
                userName = data.getStringExtra("user_name");
                userId = Integer.parseInt(data.getStringExtra("user_id"));
                Log.d(TAG, userName + userId);
                connectToServer();
                getContacts();
            }
        }
    }

    private void getContacts() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(SimpleService.BASE_URL)
                .build();
        SimpleService.ServerAPI service = retrofit.create(SimpleService.ServerAPI.class);
        Call<ResponseBody> call = service.get_contacts(userName);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call,
                                   Response<ResponseBody> response) {
                JSONObject responseJson = Util.parseResponse(response, TAG);
                if (response.code() == 200) {
                    fillContacts(responseJson.optJSONArray("contacts"));
                } else {
                    toast(responseJson.optString("detail"));
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                // Log error here since request failed
                toast("cannot connect to server");
                t.printStackTrace();
            }
        });
    }

    private void fillContacts(final JSONArray contacts) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                ArrayList<Map<String, Object>> contactsList = new ArrayList<>();
                contacts_infos = new HashMap<Integer, Map<String, String>>();
                contacts_map = new HashMap<String, Map<String, String>>();
                for(int i = 0; i < contacts.length(); i++) {
                    Log.d(TAG, contacts.optJSONObject(i).toString());
                    Map<String, String> contacts_info = new HashMap<String, String>();
                    contacts_info.put("user_id",
                            String.valueOf(contacts.optJSONObject(i).optInt("user_id")));
                    contacts_info.put("name", contacts.optJSONObject(i).optString("name"));
                    contacts_info.put("logo", contacts.optJSONObject(i).optString("logo"));
                    contacts_info.put("nickname", contacts.optJSONObject(i).optString("nickname"));
                    contacts_info.put("aliasname", contacts.optJSONObject(i).optString("aliasname"));
                    contacts_infos.put(i, contacts_info);
                    contacts_map.put(contacts.optJSONObject(i).optString("name"), contacts_info);

                    Map<String, Object> map = new HashMap<>();
                    map.put("contacts_img", R.mipmap.ic_launcher);
                    map.put("contacts_name", contacts.optJSONObject(i).optString("display_name"));
                    contactsList.add(map);
                }

                SimpleAdapter simpleAdapter = new SimpleAdapter(
                        MainActivity.this, contactsList, R.layout.contacts,
                        new String[] {"contacts_img", "contacts_name"},
                        new int[] {R.id.contacts_img, R.id.contacts_name});
                contacts_view.setAdapter(simpleAdapter);
                contacts_view.setOnItemClickListener(MainActivity.this);
            }
        });

    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Log.d(TAG, position + ": " + contacts_infos.get(position).toString());
        if(websocketClient == null ||
                websocketClient.getReadyState() != WebSocket.READYSTATE.OPEN) {
            toast("connecting to server, retry a little while");
        }

        String peerName = contacts_infos.get(position).get("name");
        Log.d(TAG, peerName + ": " + contacts_map.toString());
        Log.d(TAG, userId + ":" + Integer.parseInt(contacts_map.get(peerName).get("user_id")));
        Intent intent = new Intent(MainActivity.this, ChatActivity.class);
        intent.putExtra("userName", userName);
        intent.putExtra("peerName", peerName);
        intent.putExtra("userId", userId);
        intent.putExtra("peerId", Integer.parseInt(contacts_map.get(peerName).get("user_id")));
        startActivityForResult(intent, REQUEST_CHAT);

    }

    private void connectToServer() {
        try {
            String mSocketAddress = "ws://p2p0.reconova.com:3000";
            Log.d(TAG, mSocketAddress);
            websocketClient = new WebSocketClient(new URI(mSocketAddress), new Draft_17()) {
                @Override
                public void onMessage(String message) {
                    Log.d(TAG, "got: " + message + "\n");
                    try {
                        JSONObject data = new JSONObject(message);
                        getMessage(data);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onOpen(ServerHandshake handshake) {
                    Log.d(TAG, "You are connected to ChatServer: " + getURI() + "\n");
                    try {
                        JSONObject payload = new JSONObject();
                        payload.put("type", "signal-login");
                        payload.put("name", userName);
                        websocketClient.send(payload.toString());
                        Thread.sleep(500);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onClose(int code, String reason, boolean remote) {
                    Log.d(TAG, "You have been disconnected from: " + getURI() +
                            "; Code: " + code + " " + reason + "\n");
                }

                @Override
                public void onError(Exception ex) {
                    Log.d(TAG, "Exception occured ...\n" + ex + "\n");
                    ex.printStackTrace();
                }
            };
            websocketClient.connectBlocking();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void getMessage(JSONObject data) {
        try {
            String type = data.getString("type");
            String from = data.optString("from");
            if (type.equals("signal-login")) {
                boolean login_result = data.getBoolean("success");
                if (login_result == true) {
                    Log.d(TAG, "LoginCommand: success");
                    loginInSuccess = true;
                    toast("connected");
                    Thread thread=new Thread(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            Log.d(TAG, "Thread start");
                            while(loginInSuccess) {
                                try {
                                    List<Map<String, String>> messages =  dbManager.queryUnSendMessage();
                                    if(messages.size() > 0) {
                                        JSONObject message = new JSONObject();
                                        message.put("type", "signal-message");
                                        message.put("name", "");
                                        message.put("payload", messages);
                                        Log.d(TAG, message.toString());
                                        websocketClient.send(message.toString());
                                    }
                                    JSONObject message_info = new JSONObject();
                                    for(int i = 0; i < messages.size(); i++) {
                                        message_info.put(messages.get(i).get("id"),
                                                messages.get(i).get("message_id"));
                                    }
                                    dbManager.updateMessageId(message_info);
                                    Thread.sleep(200);
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    });
                    thread.start();
                } else {
                    Log.d(TAG, "Ooops...try a different username");
                }
            } else if(type.equals("message_send_success")) {
                JSONObject message_ids = data.optJSONObject("payload");
                dbManager.updateMessageId(message_ids);
            } else if(type.equals("message")) {
                dbManager.addMessage(Integer.parseInt(contacts_map.get(from).get("user_id")), userId,
                        data.optJSONObject("payload").optString("content"), 1,
                        Long.parseLong(data.optJSONObject("payload").optString("create_time")));
            /*} else if (type.equals("signal-call")) {
                Intent intent = new Intent(MainActivity.this, CallActivity.class);
                intent.putExtra("userName", userName);
                intent.putExtra("peerName", from);
                intent.putExtra("loopback", "true");
                startActivityForResult(intent, REQUEST_CONNECTION);
            } else if (type.equals("signal-file-transform")) {
                Intent intent = new Intent(MainActivity.this, FileTransformActivity.class);
                intent.putExtra("userName", userName);
                intent.putExtra("filePath", data.optJSONObject("payload").optString("filePath"));
                intent.putExtra("fileSize", data.optJSONObject("payload").optInt("fileSize"));
                intent.putExtra("peerName", from);
                intent.putExtra("loopback", "true");
                startActivityForResult(intent, REQUEST_FILE_TRANSFORM);*/
            } else {
                Log.d(TAG, "Ooops...Command not found");
            }
        }catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    public void onDestroy() {
        loginInSuccess = false;
        super.onDestroy();
    }

    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("Confirm");
            builder.setMessage("Are you sure to exit?");
            builder.setPositiveButton("YES", mDlgClick);
            builder.setNegativeButton("NO", mDlgClick);
            builder.show();
            return true;
        }
        return super.onKeyUp(keyCode, event);
    }

    private DialogInterface.OnClickListener mDlgClick = new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            if (which == AlertDialog.BUTTON_POSITIVE) {
                android.os.Process.killProcess(android.os.Process.myPid());
            }
        }
    };
}
